import { Ref, SetupContext, computed, defineComponent, inject, onMounted, provide, ref, watch, onBeforeUnmount } from 'vue';
import { DesignerItemPropsType, designerItemProps } from '../composition/props/designer-item.props';
import { componentMap, componentPropsConverter } from './maps';
import { DesignerHTMLElement, UseDragula } from '../composition/types';
import { ComponentSchema, DesignerComponentInstance, DesignerItemContext } from '../types';
import FDesignerPlaceholder from './designer-placeholder.component';
import { cavasChanged, setPositionOfBtnGroup } from '../composition/designer-cavas-changed';

const FDesignerItem = defineComponent({
    name: 'FDesignerItem',
    props: designerItemProps,
    emits: [],
    setup(props: DesignerItemPropsType, context: SetupContext) {
        const id = ref(`${props.modelValue.id}-component`);
        const canMove = ref(props.canMove);
        const canDelete = ref(props.canDelete);
        const canNested = ref(false);
        const schema = ref(props.modelValue);
        const designComponentStyle = ref('');
        const designerItemElementRef = ref();
        const useDragulaComposition = inject<UseDragula>('canvas-dragula');
        const componentInstance = ref() as Ref<DesignerComponentInstance>;
        const parent = inject<DesignerItemContext>('design-item-context');
        const designItemContext = { designerItemElementRef, componentInstance, schema: schema.value, parent };
        provide<DesignerItemContext>('design-item-context', designItemContext);

        const designerItemClass = computed(() => {
            const componentClass = props.modelValue.appearance ? (props.modelValue.appearance.class as string) || '' : '';
            const classObject = {
                'farris-component': true,
                'position-relative': canMove.value && canDelete.value,
                'farris-nested': canNested.value,
                'can-move': canMove.value,
                'd-none': designerItemElementRef.value && (designerItemElementRef.value as HTMLElement).classList.contains('d-none')
            } as Record<string, boolean>;
            classObject[`farris-component-${schema.value.type}`] = true;
            if (componentClass) {
                componentClass.split(' ').reduce((result: Record<string, boolean>, classString: string) => {
                    result[classString] = true;
                    return result;
                }, classObject);
            }
            return classObject;
        });

        const desginerItemStyle = computed(() => {
            const styleObject = {} as Record<string, any>;
            const componentStyle = props.modelValue.appearance ? (props.modelValue.appearance.style as string) || '' : '';
            if (componentStyle) {
                componentStyle.split(';').reduce((result: Record<string, any>, styleString: string) => {
                    const [styleKey, styleValue] = styleString.split(':');
                    result[styleKey] = styleValue;
                    return result;
                }, styleObject);
            }
            if (designComponentStyle.value) {
                designComponentStyle.value.split(';').reduce((result: Record<string, any>, styleString: string) => {
                    const [styleKey, styleValue] = styleString.split(':');
                    if (styleKey) {
                        result[styleKey] = styleValue;
                    }
                    return result;
                }, styleObject);
            }
            return styleObject;
        });

        function onClickDeleteButtom(payload: MouseEvent, schemaToRemove: ComponentSchema) {
            // 连同所属组件一起删除，使用场景如data-grid、form控件等。
            if (componentInstance.value.triggerBelongedComponentToDeleteWhenDeleted) {
                const cmpInstance = componentInstance.value.getBelongedComponentInstance(componentInstance);
                if (cmpInstance && cmpInstance.parent) {
                    const cmpInstanceParent = ref(cmpInstance?.parent) as any;
                    const indexToRemove = cmpInstanceParent.value.contents.findIndex(
                        (contentItem: ComponentSchema) => contentItem.id === cmpInstance.schema.id
                    );
                    cmpInstanceParent.value?.contents?.splice(indexToRemove, 1);
                }
                return;
            }
            if (parent && parent.schema.contents) {
                const indexToRemove = parent.schema.contents.findIndex(
                    (contentItem: ComponentSchema) => contentItem.id === schemaToRemove.id
                );
                parent.schema.contents.splice(indexToRemove, 1);
            }

            // cavasChanged.value++;
        }

        function renderDeleteButton(componentSchema: ComponentSchema) {
            return (
                canDelete.value && (
                    <div
                        role="button"
                        class="btn component-settings-button"
                        title="删除"
                        ref="removeComponent"
                        onClick={(payload: MouseEvent) => {
                            onClickDeleteButtom(payload, componentSchema);
                        }}>
                        <i class="f-icon f-icon-yxs_delete"></i>
                    </div>
                )
            );
        }

        function renderMoveButton() {
            return (
                canMove.value && (
                    <div role="button" class="btn component-settings-button" title="移动" ref="moveComponent">
                        <i data-dragging-icon="true" class="cmp_move f-icon f-icon-yxs_move"></i>
                    </div>
                )
            );
        }

        function renderSelectParentButton() {
            return (
                props.canSelectParent && (
                    <div role="button" class="btn component-settings-button" title="选中上层" ref="selectParentComponent">
                        <i data-dragging-icon="true" class="cmp_move f-icon f-icon-enclosure_upload"></i>
                    </div>
                )
            );
        }

        function renderCustomButtons() {
            return (
                props.customButtons &&
                !!props.customButtons.length &&
                props.customButtons.map((buttonConfig: any) => {
                    return (
                        <div
                            role="button"
                            class={`btn component-settings-button ${buttonConfig.class || ''}`}
                            title={buttonConfig.title}
                            ref={buttonConfig.id}>
                            <i class={buttonConfig.icon}></i>
                        </div>
                    );
                })
            );
        }

        function renderIconPanel(componentSchema: ComponentSchema) {
            return (
                <div class="component-btn-group" data-noattach="true">
                    <div>
                        {renderDeleteButton(componentSchema)}
                        {renderMoveButton()}
                        {renderCustomButtons()}
                    </div>
                </div>
            );
        }

        function renderContent(viewSchema: ComponentSchema) {
            const componentKey = viewSchema.type;
            const Component = componentMap[componentKey];

            const propsConverter = componentPropsConverter[componentKey];
            const viewProps = propsConverter ? propsConverter(viewSchema) : {};
            viewProps.customClass = props.ignore ? viewProps.customClass : '';
            const shouldShowPlaceholder = viewSchema.contents && viewSchema.contents.length === 0;
            const hasContent = viewSchema.contents && !!viewSchema.contents.length;
            return hasContent && Component ? (
                <Component ref={componentInstance} {...viewProps}>
                    {(viewSchema.contents as ComponentSchema[]).map((contentSchema: any) => (
                        <FDesignerItem key={contentSchema.id} v-model={contentSchema}></FDesignerItem>
                    ))}
                </Component>
            ) : Component ? (
                shouldShowPlaceholder ? (
                    <Component ref={componentInstance} {...viewProps}>
                        <FDesignerPlaceholder></FDesignerPlaceholder>
                    </Component>
                ) : (
                    <Component ref={componentInstance} {...viewProps}></Component>
                )
            ) : (
                <div></div>
            );
        }

        watch(
            () => props.modelValue,
            (value: any) => {
                schema.value = value;
                id.value = `${value.id}-component`;
            }
        );

        onMounted(() => {
            if (designerItemElementRef.value && componentInstance.value) {
                const draggableContainer = designerItemElementRef.value.querySelector(
                    `[data-dragref='${componentInstance.value.schema.id}-container']`
                );
                // const draggableContainer = (designerItemElementRef.value as HTMLElement).parentElement as HTMLElement;
                if (useDragulaComposition && draggableContainer) {
                    useDragulaComposition.attachComponents(draggableContainer, schema.value);
                }
                canNested.value = componentInstance.value.canNested !== undefined ? componentInstance.value.canNested : canNested.value;
                canDelete.value = componentInstance.value.canDelete !== undefined ? componentInstance.value.canDelete : canDelete.value;
                canMove.value = componentInstance.value.canMove !== undefined ? componentInstance.value.canMove : canMove.value;
                designComponentStyle.value = componentInstance.value.styles || '';
                if (designerItemElementRef.value) {
                    designerItemElementRef.value.componentInstance = componentInstance;
                }
            }
            bindingScrollEvent();

            cavasChanged.value++;
        });

        function bindingScrollEvent() {
            if (schema.value?.contents?.length && designerItemElementRef.value) {
                designerItemElementRef.value.addEventListener('scroll', updatePositionOfBtnGroup);
            }
        }

        function updatePositionOfBtnGroup(e: Event) {
            const targetEl = e.target as any;
            setPositionOfBtnGroup(targetEl);
        }

        onBeforeUnmount(() => {
            if (designerItemElementRef.value) {
                designerItemElementRef.value.removeEventListener('scroll', updatePositionOfBtnGroup);
            }
        });

        function onClickDesignerItem(payload: MouseEvent) {
            Array.from(document.getElementsByClassName('dgComponentFocused') as HTMLCollectionOf<HTMLElement>).forEach(
                (element: HTMLElement) => element.classList.remove('dgComponentFocused')
            );
            if (payload) {
                payload.preventDefault();
                payload.stopPropagation();
            }
            const designerItemElement = designerItemElementRef.value as HTMLElement;
            if (designerItemElement) {
                const currentSelectedElements = document.getElementsByClassName('dgComponentSelected') as HTMLCollectionOf<HTMLElement>;
                // 重复点击
                const duplicateClick =
                    currentSelectedElements &&
                    currentSelectedElements.length === 1 &&
                    currentSelectedElements[0] === designerItemElementRef.value;
                if (!duplicateClick) {
                    Array.from(currentSelectedElements).forEach((element: HTMLElement) => element.classList.remove('dgComponentSelected'));

                    designerItemElement.classList.add('dgComponentFocused');
                    const draggabledesignerItemElementRef = componentInstance.value.getDraggableDesignItemElement(designItemContext);
                    if (draggabledesignerItemElementRef && draggabledesignerItemElementRef.value) {
                        draggabledesignerItemElementRef.value.classList.add('dgComponentSelected');
                    }
                    // const draggableContainer = designerItemElement.querySelector(
                    //     `[data-dragref='${componentInstance.value.schema.id}-container']`
                    // );
                    // const associateElementId = draggableContainer ? draggableContainer.getAttribute('data-associate') : '';
                    // if (associateElementId) {
                    //     const associateElement = document.getElementById(`${associateElementId}-design-item`);
                    //     if (associateElement) {
                    //         associateElement.classList.add('dgComponentSelected');
                    //     }
                    // }
                }
            }

            cavasChanged.value++;
        }

        return () => {
            return (
                <div
                    id={`${schema.value.id}-design-item`}
                    ref={designerItemElementRef}
                    class={designerItemClass.value}
                    style={desginerItemStyle.value}
                    onClick={onClickDesignerItem}>
                    {renderIconPanel(schema.value)}
                    {renderContent(schema.value)}
                </div>
            );
        };
    }
});
export default FDesignerItem;
